﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Platformer;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
using System.IO;

namespace SilverXNA
{
	public partial class GamePage : PhoneApplicationPage
	{
		ContentManager contentManager;
		GameTimer timer;
		SpriteBatch spriteBatch;

		// Global content.
		private SpriteFont hudFont;

		// Meta-level game state.
		private int levelIndex = -1;
		private bool wasContinuePressed;

		// We store our input states so that we only poll once per frame, 
		// then we use the same input state wherever needed
		private GamePadState gamePadState;
		private KeyboardState keyboardState;
		private TouchCollection touchState;
		private AccelerometerState accelerometerState;

		// The number of levels in the Levels directory of our content. We assume that
		// levels in our content are 0-based and that all numbers under this constant
		// have a level file present. This allows us to not need to check for the file
		// or handle exceptions, both of which can add unnecessary time to level loading.
		private const int numberOfLevels = 3;

		// For rendering the XAML onto a texture
		UIElementRenderer elementRenderer;
		int elementRendererHeight;
		int elementRendererWidth;

		ViewModel.GameViewModel vm;

		public GamePage()
		{
			InitializeComponent();

			// Get the content manager from the application
			contentManager = (Application.Current as App).Content;

			vm = this.DataContext as ViewModel.GameViewModel;

			// Create a timer for this page
			timer = new GameTimer();
			timer.UpdateInterval = TimeSpan.FromTicks(333333);
			timer.Update += OnUpdate;
			timer.Draw += OnDraw;

			Accelerometer.Initialize();
			// Use the LayoutUpdate event to know when the page layout 
			// has completed so that we can create the UIElementRenderer.
			LayoutUpdated += new EventHandler(GamePage_LayoutUpdated);
		}

		void GamePage_LayoutUpdated(object sender, EventArgs e)
		{
			// Create the UIElementRenderer to draw the XAML page to a texture.

			// Check for 0 because when we navigate away the LayoutUpdate event
			// is raised but ActualWidth and ActualHeight will be 0 in that case.
			if ((ActualWidth > 0) && (ActualHeight > 0))
			{
				SharedGraphicsDeviceManager.Current.PreferredBackBufferWidth = (int)ActualWidth;
				SharedGraphicsDeviceManager.Current.PreferredBackBufferHeight = (int)ActualHeight;

				if ((int)ActualHeight != elementRendererHeight || (int)ActualWidth != elementRendererWidth)
				{
					elementRenderer = new UIElementRenderer(this, (int)ActualWidth, (int)ActualHeight);
					elementRendererHeight = (int)ActualHeight;
					elementRendererWidth = (int)ActualWidth;
				}
			}

			if (null == elementRenderer)
			{
				elementRenderer = new UIElementRenderer(this, (int)ActualWidth, (int)ActualHeight);
			}
		}

		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
			// Set the sharing mode of the graphics device to turn on XNA rendering
			SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

			// Create a new SpriteBatch, which can be used to draw textures.
			spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

			// TODO: use this.content to load your game content here
			LoadContent();

			// Start the timer
			timer.Start();

			base.OnNavigatedTo(e);
		}

		/// <summary>
		/// LoadContent will be called once per game and is the place to load
		/// all of your content.
		/// </summary>
		void LoadContent()
		{
			// Load fonts
			hudFont = contentManager.Load<SpriteFont>("Fonts/Hud");

			//Known issue that you get exceptions if you use Media PLayer while connected to your PC
			//See http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/c8a243d2-d360-46b1-96bd-62b1ef268c66
			//Which means its impossible to test this from VS.
			//So we have to catch the exception and throw it away
			try
			{
				MediaPlayer.IsRepeating = true;
				MediaPlayer.Play(contentManager.Load<Song>("Sounds/Music"));
			}
			catch { }

			LoadNextLevel();
		}

		protected override void OnNavigatedFrom(NavigationEventArgs e)
		{
			// Stop the timer
			timer.Stop();

			// Set the sharing mode of the graphics device to turn off XNA rendering
			SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

			base.OnNavigatedFrom(e);
		}

		/// <summary>
		/// Allows the page to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		private void OnUpdate(object sender, GameTimerEventArgs e)
		{
			// TODO: Add your update logic here
			// Handle polling for our input and handling high-level input
			HandleInput();

			// update our level, passing down the GameTime along with all of our input states
			vm.GameLevel.Update(e.ElapsedTime, keyboardState, gamePadState, touchState,
						 accelerometerState, this.Orientation.ToXNAOrientation());

			vm.GameTime = vm.GameLevel.TimeRemaining;
			vm.GameScore = vm.GameLevel.Score;
		}

		/// <summary>
		/// Allows the page to draw itself.
		/// </summary>
		private void OnDraw(object sender, GameTimerEventArgs e)
		{
			// Render the Silverlight controls using the UIElementRenderer.
			elementRenderer.Render();
			
			SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);

			// TODO: Add your drawing code here
			spriteBatch.Begin();
			
			vm.GameLevel.Draw(e.ElapsedTime, spriteBatch);

			// Using the texture from the UIElementRenderer, 
			// draw the Silverlight controls to the screen.
			spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);

			spriteBatch.End();
		}

		private void HandleInput()
		{
			touchState = TouchPanel.GetState();
			accelerometerState = Accelerometer.GetState();


			bool continuePressed = touchState.AnyTouch();

			// Perform the appropriate action to advance the game and
			// to get the player back to playing.
			if (!wasContinuePressed && continuePressed)
			{
				if (!vm.GameLevel.Player.IsAlive)
				{
					vm.GameLevel.StartNewLife();
				}
				else if (vm.GameLevel.TimeRemaining == TimeSpan.Zero)
				{
					if (vm.GameLevel.ReachedExit)
						LoadNextLevel();
					else
						ReloadCurrentLevel();
				}
			}

			wasContinuePressed = continuePressed;
		}

		private void LoadNextLevel()
		{
			// move to the next level
			levelIndex = (levelIndex + 1) % numberOfLevels;

			// Unloads the content for the current level before loading the next one.
			if (vm.GameLevel != null)
				vm.GameLevel.Dispose();

			// Load the vm.GameLevel.
			string levelPath = string.Format("Content/Levels/{0}.txt", levelIndex);
			using (Stream fileStream = TitleContainer.OpenStream(levelPath))
				vm.GameLevel = new Level((Application.Current as App).Services, fileStream, levelIndex);
		}

		private void ReloadCurrentLevel()
		{
			--levelIndex;
			LoadNextLevel();
		}
	}

	public static class OrientationExtensions
	{
		public static DisplayOrientation ToXNAOrientation(this PageOrientation input)
		{
			switch (input)
			{
				case PageOrientation.Landscape:
				case PageOrientation.LandscapeLeft:
					return DisplayOrientation.LandscapeLeft;
				case PageOrientation.LandscapeRight:
					return DisplayOrientation.LandscapeRight;
				default:
					return DisplayOrientation.Portrait;
			}
		}
	}
}